package com.fa4j.common.feign.decoder;

import com.fa4j.common.web.model.ResponseVO;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.FeignException;
import feign.Request;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Map;

@Slf4j
@RequiredArgsConstructor
public class ResponseWrapperFeignDecoder implements Decoder {

    private final ObjectMapper objectMapper;

    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        // 1. 读取响应体
        String bodyString = Util.toString(response.body().asReader(Util.UTF_8));
        // 2. 构建正确的泛型类型信息: ResponseVO<T>
        JavaType parameterType = objectMapper.getTypeFactory().constructType(type);
        JavaType resultType = objectMapper.getTypeFactory().constructParametricType(ResponseVO.class, parameterType);
        // 3. 反序列化
        ResponseVO<?> result = objectMapper.readValue(bodyString, resultType);
        Request request = response.request();
        String requestBody = getRequestBody(response);
        requestBody = requestBody == null ? "" : ",请求:" + requestBody;
        if (!result.isSuccess()) {
            // 4.结果异常处理
            log.error("[{}:{}]{},返回异常[{}]:{}", request.httpMethod(), request.url(), requestBody, result.getErrCode(), bodyString);
            throw new FeignResponseException("Feign接口调用返回:" + result.getErrMsg(), result.getErrCode(), result.getErrMsg());
        } else {
            log.info("[{}:{}]{},响应:{}", request.httpMethod(), request.url(), requestBody, bodyString);
        }
        // 5. 返回核心数据
        return result.getData();
    }

    private String getRequestBody(Response response) {
        Request request = response.request();
        if (ObjectUtils.isEmpty(request.body()) || !isApplicationJson(request.headers())) {
            return null;
        }
        return new String(request.body(), StandardCharsets.UTF_8);
    }

    private boolean isApplicationJson(Map<String, Collection<String>> headers) {
        if (ObjectUtils.isEmpty(headers) || ObjectUtils.isEmpty(headers.get(HttpHeaders.CONTENT_TYPE))) {
            return false;
        }
        MediaType mediaType = null;
        for (String contentType : headers.get(HttpHeaders.CONTENT_TYPE)) {
            mediaType = MediaType.parseMediaType(contentType);
        }
        return MediaType.APPLICATION_JSON.equals(mediaType);
    }
}
